package cn.texous.starter.sms.service;

import cn.texous.starter.sms.config.properties.SmsProperties;
import cn.texous.starter.sms.handler.SmsHandler;
import cn.texous.starter.sms.model.SendInfo;
import cn.texous.starter.sms.model.SendResult;
import lombok.extern.slf4j.Slf4j;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2019/8/23 10:30
 */
@Slf4j
public class SmsService {

    private SmsProperties smsProperties;
    private List<SmsHandler> smsHandlers;
    private Map<String, SmsHandler> smsHandlerMap;

    public SmsService(Map<String, SmsHandler> smsHandlerMap,
                      SmsProperties smsProperties) {
        this.smsHandlerMap = smsHandlerMap;
        Set<SmsHandler> handlers = new HashSet<>();
        Iterator<SmsHandler> smsHandlerIterator = smsHandlerMap.values().iterator();
        while (smsHandlerIterator.hasNext())
            handlers.add(smsHandlerIterator.next());

        this.smsHandlers = handlers.stream()
                .sorted(Comparator.comparing(SmsHandler::order))
                .collect(Collectors.toList());

        this.smsProperties = smsProperties;
    }

    /**
     * 发送消息
     * @param sendInfo param
     * @return
     */
    public SendResult sendSms(SendInfo sendInfo) {
        SendResult sendResult = new SendResult();
        String smsHandlerStr;

        if (sendInfo.getPlatform() != null) {
            smsHandlerStr = sendInfo.getPlatform().loadSmsHandler();
            SmsHandler smsHandler = smsHandlerMap.get(smsHandlerStr);
            send(sendInfo, sendResult, smsHandler);
            if (sendResult.success()
                    || !smsProperties.getAutoSwitch()
                    || !sendInfo.isAutoSwitch())
                return sendResult;
        } else {
            SmsHandler smsHandler = smsHandlers.get(0);
            smsHandlerStr = smsHandler.getClass().getSimpleName();
            smsHandlerStr = smsHandlerStr.substring(0, 1)
                    .toLowerCase() + smsHandlerStr.substring(1);

            send(sendInfo, sendResult, smsHandler);
            if (sendResult.success()
                    || !smsProperties.getAutoSwitch()
                    || !sendInfo.isAutoSwitch())
                return sendResult;
        }
        // 发送失败后，切换通道发送
        foreachSend(sendInfo, sendResult, smsHandlerStr);
        return sendResult;
    }

    private void foreachSend(SendInfo sendInfo,
                             SendResult sendResult,
                             String... exclusions) {
        Set<SmsHandler> exHandlers = new HashSet<>();
        if (exclusions != null) {
            for (String eh : exclusions) {
                exHandlers.add(smsHandlerMap.get(eh));
            }
        }

        for (int i = 0; i < smsHandlers.size() && !sendResult.success(); i++) {
            SmsHandler handler = smsHandlers.get(i);
            if (!exHandlers.isEmpty()
                    && exHandlers.contains(handler))
                continue;

            send(sendInfo, sendResult, handler);
        }

    }

    private void send(SendInfo sendInfo,
                      SendResult sendResult,
                      SmsHandler smsHandler) {
        if (smsHandler != null && smsHandler.init()) {
            SendResult result = smsHandler.send(sendInfo);
            sendResult.setCode(result.getCode());
            sendResult.setChannel(result.getChannel());
            sendResult.setErrorCode(result.getErrorCode());
            sendResult.setErrorMsg(result.getErrorMsg());
            if (!result.success())
                sendResult.addError(result);
        } else {
            SendResult result = new SendResult(smsHandler.channel());
            result.setErrorCode("smsHandlerNotInitError");
            result.setErrorMsg("该平台短信发送方式没有初始化");
            sendResult.setCode(result.getCode());
            sendResult.setChannel(result.getChannel());
            sendResult.setErrorCode(result.getErrorCode());
            sendResult.setErrorMsg(result.getErrorMsg());
            sendResult.addError(result);
        }
    }

}
